unit dxSkinsdxExplorerBarView;

interface

uses
  Types, Windows, Graphics, Classes, ImgList,
  dxNavBar, dxNavBarBase, dxNavBarCollns, dxNavBarStyles, dxNavBarExplorerViews,
  dxNavBarGraphics, dxNavBarOffice11Views, dxNavBarOfficeViews,
  cxLookAndFeels, cxLookAndFeelPainters,cxGraphics, cxClasses, dxSkinInfo,
  dxNavBarSkinBasedViews, dxSkinsCore, dxSkinsLookAndFeelPainter,
  dxNavBarCustomPainters, dxOffice11;

const
  dxNavBarSkinExplorerBarView = 20;

type
  TdxNavBarSkinVista2PainterHelper = class(TdxNavBarSkinBasedPainterHelper)
  private
    FLookAndFeel: TcxLookAndFeel;
  protected
    function GetSkinsCount: Integer; override;
    function GetSkinNames(AIndex: Integer): TdxSkinName; override;
    function GetSkinInfoClass: TdxSkinInfoClass; override;
    function GetSkinName: TdxSkinName; override;
    function GetSkinPainterData(var AData: TdxSkinInfo): Boolean; override;
    procedure LookAndFeelChanged(Sender: TcxLookAndFeel; AChangedValues: TcxLookAndFeelValues);
    procedure SetSkinName(AValue: TdxSkinName); override;
  public
    constructor Create(ASkinName: TdxSkinName); override;
    destructor Destroy; override;

    function NavPaneDoesGroupCaptionButtonRequireOffset: Boolean; override;
    function NavPanePopupControl: TdxSkinElement; override;

    function NavBarDragDropItemTarget: TdxSkinElement; override;
    function NavBarSeparator: TdxSkinElement; override;
  end;

  { TdxNavBarSkinVista2ExplorerBarViewInfo }

  TdxNavBarSkinVista2ExplorerBarViewInfo = class(TdxNavBarExplorerBarViewInfo)
  protected
    function GetHelper: TdxNavBarSkinVista2PainterHelper;
    function GetGroupCaptionSignSize: TSize; override;

    function CanSelectLinkByRect: Boolean; override;
    function GetAbsoluteLinksImageEdges: TRect; override;
    function GetGroupBorderOffsets: TRect; override;
    class function GetGroupCaptionImageIndent: Integer; override;
    function GetGroupCaptionHeightAddon: Integer; override;
    function GetGroupEdges: TPoint; override;
    function GetGroupSeparatorWidth: Integer; override;

    // Link
    class function GetLinksSmallSeparatorWidth: Integer; override;
  public
    procedure AssignDefaultItemHotTrackedStyle; override;
    procedure AssignDefaultItemPressedStyle; override;
  end;

  { TdxNavBarSkinVista2ExplorerBarPainter }

  TdxNavBarSkinVista2ExplorerBarPainter = class(TdxNavBarSkinBasedExplorerBarPainter)
  private
    function GetLookAndFeel: TcxLookAndFeel;
    function GetSkinName: TdxSkinName;
    function GetSkinNameAssigned: Boolean;
    function IsSkinNameStored: Boolean;
    procedure SetLookAndFeel(AValue: TcxLookAndFeel);
    procedure SetSkinName(const AValue: TdxSkinName);
    procedure SetSkinNameAssigned(AValue: Boolean);
  protected
    class function GetGroupViewInfoClass: TdxNavBarGroupViewInfoClass; override;
    class function GetLinkViewInfoClass: TdxNavBarLinkViewInfoClass; override;
    class function GetViewInfoClass: TdxNavBarViewInfoClass; override;
    class function GetSkinPainterHelperClass: TdxNavBarSkinBasedPainterHelperClass; override;
    class function SignPainterClass: TdxNavBarCustomSignPainterClass; override;
    class function SelectionPainterClass: TdxNavBarCustomSelectionPainterClass; override;

    procedure DrawGroupTopBorder(AGroupViewInfo: TdxNavBarGroupViewInfo);
    function GetMasterLookAndFeel: TcxLookAndFeel; override;
  public
    procedure Assign(Source: TPersistent); override;
    procedure DrawItemSelection(ALinkViewInfo: TdxNavBarLinkViewInfo); override;
    procedure DrawBackground; override;
    procedure DrawGroupBackground(AGroupViewInfo: TdxNavBarGroupViewInfo); override;
    procedure DrawGroupBorder(AGroupViewInfo: TdxNavBarGroupViewInfo); override;
    procedure DrawGroupControl(ACanvas: TCanvas; ARect: TRect;
      AGroupViewInfo: TdxNavBarGroupViewInfo); override;
    procedure DrawGroupControlSplitter(AGroupViewInfo: TdxNavBarExplorerBarGroupViewInfo); override;
    procedure DrawSeparator(ALinkViewInfo: TdxNavBarLinkViewInfo); override;
    property LookAndFeel: TcxLookAndFeel read GetLookAndFeel write SetLookAndFeel;
  published
    property SkinName: TdxSkinName read GetSkinName write SetSkinName stored IsSkinNameStored;
    property SkinNameAssigned: Boolean read GetSkinNameAssigned write SetSkinNameAssigned default False;
  end;

  TdxNavBarSkinVista2ExplorerBarSelectionPainter = class(TdxNavBarCustomSelectionPainter)
  protected
    class procedure GetColors(AState: TdxNavBarObjectStates; ABackColor: TColor; out AFillColor,
      ATopLeftOuterColor, ABottomRightOuterColor, ATopLeftInnerColor, ABottomRightInnerColor: TColor); override;
  end;

  { TdxNavBarSkinPopupControlViewInfo }

  TdxNavBarSkinPopupControlViewInfo = class(TdxNavBarSkinBasedPopupControlViewInfo)
  protected
    function GetBorderOffsets: TRect; override;
  end;

  TdxNavBarSkinVista2ExplorerBarLinkViewInfo = class(TdxNavBarSkinBasedExplorerBarLinkViewInfo)
  public
    function Font: TFont; override;
    function FontColor: TColor; override;
  end;

  TdxNavBarSkinVista2ExplorerBarGroupViewInfo = class(TdxNavBarExplorerBarGroupViewInfo)
  protected
    function GetSplitterSize: Integer; override;
  public
    function CaptionBackColor: TColor; override;
    function CaptionBackColor2: TColor; override;
    function CaptionFont: TFont; override;
    function CaptionFontColor: TColor; override;
  end;

implementation

uses
  dxNavBarViewsFact, Math, cxGeometry, dxUxTheme;

type
  TdxCustomNavBarAccess = class(TdxCustomNavBar);

procedure DrawElementPart(AElement: TdxSkinElement; ACanvas: TcxCanvas; ADrawRect, AClipRect: TRect);
begin
  if AElement = nil then Exit;
  ACanvas.SaveClipRegion;
  try
    ACanvas.SetClipRegion(TcxRegion.Create(AClipRect), roIntersect);
    AElement.Draw(ACanvas.Handle, ADrawRect);
  finally
    ACanvas.RestoreClipRegion;
  end;
end;

{ TdxNavBarSkinVista2PainterHelper }

constructor TdxNavBarSkinVista2PainterHelper.Create(ASkinName: TdxSkinName);
begin
  inherited Create(ASkinName);
  FLookAndFeel := TcxLookAndFeel.Create(nil);
  FLookAndFeel.NativeStyle := False;
  FLookAndFeel.OnChanged := LookAndFeelChanged;
end;

destructor TdxNavBarSkinVista2PainterHelper.Destroy;
begin
  FLookAndFeel.Free;
  inherited;
end;

function TdxNavBarSkinVista2PainterHelper.NavBarDragDropItemTarget: TdxSkinElement;
begin
  Result := nil;
end;

function TdxNavBarSkinVista2PainterHelper.NavBarSeparator: TdxSkinElement;
begin
  Result := nil;
end;

function TdxNavBarSkinVista2PainterHelper.NavPaneDoesGroupCaptionButtonRequireOffset: Boolean;
var
  ABoolProperty: TdxSkinBooleanProperty;
  ASkinInfo: TdxSkinInfo;
begin
  if GetSkinPainterData(ASkinInfo) then
    ABoolProperty := ASkinInfo.NavPaneOffsetGroupBorders
  else
    ABoolProperty := nil;

  if ABoolProperty = nil then
    Result := inherited NavPaneDoesGroupCaptionButtonRequireOffset
  else
    Result := ABoolProperty.Value;
end;

function TdxNavBarSkinVista2PainterHelper.NavPanePopupControl: TdxSkinElement;
var
  ASkinInfo: TdxSkinInfo;
begin
  Result := nil;
  if GetSkinPainterData(ASkinInfo) then
    Result := ASkinInfo.NavPaneFormBorder;
end;

function TdxNavBarSkinVista2PainterHelper.GetSkinsCount: Integer;
begin
  Result := GetExtendedStylePainters.Count;
end;

function TdxNavBarSkinVista2PainterHelper.GetSkinNames(AIndex: Integer): TdxSkinName;
begin
  Result := GetExtendedStylePainters.Names[AIndex];
end;

function TdxNavBarSkinVista2PainterHelper.GetSkinInfoClass: TdxSkinInfoClass;
begin
  Result := TdxSkinInfo;
end;

function TdxNavBarSkinVista2PainterHelper.GetSkinName: TdxSkinName;
begin
  Result := FLookAndFeel.SkinName;
end;

function TdxNavBarSkinVista2PainterHelper.GetSkinPainterData(var AData: TdxSkinInfo): Boolean;
begin
  Result := GetExtendedStylePainters.GetPainterData(FLookAndFeel.SkinPainter, AData);
end;

procedure TdxNavBarSkinVista2PainterHelper.LookAndFeelChanged(Sender: TcxLookAndFeel; AChangedValues: TcxLookAndFeelValues);
begin
  DoChanged;
end;

procedure TdxNavBarSkinVista2PainterHelper.SetSkinName(AValue: TdxSkinName);
begin
  FLookAndFeel.SkinName := AValue;
end;

{ TdxNavBarSkinPopupControlViewInfo }

function TdxNavBarSkinPopupControlViewInfo.GetBorderOffsets: TRect;
var
  AElement: TdxSkinElement;
begin
  AElement := GetSkinHelper.NavPanePopupControl;
  if AElement <> nil then
    if not AElement.Image.Empty then
      Result := AElement.Image.Margins.Rect
    else
      with AElement.Borders do
        Result := cxRect(Left.Thin, Top.Thin, Right.Thin, Bottom.Thin)
  else
    Result := inherited GetBorderOffsets;
end;

{ TdxNavBarSkinVista2ExplorerBarViewInfo }

function TdxNavBarSkinVista2ExplorerBarViewInfo.GetHelper: TdxNavBarSkinVista2PainterHelper;
begin
  Result := TdxNavBarSkinVista2PainterHelper(TdxNavBarSkinVista2ExplorerBarPainter(Painter).FSkinBasedPainterHelper);
end;

class function TdxNavBarSkinVista2ExplorerBarViewInfo.GetLinksSmallSeparatorWidth: Integer;
begin
  Result := 15;
end;

procedure TdxNavBarSkinVista2ExplorerBarViewInfo.AssignDefaultItemHotTrackedStyle;
begin
  inherited AssignDefaultItemHotTrackedStyle;
  NavBar.DefaultStyles.ItemHotTracked.Font.Style := NavBar.DefaultStyles.ItemHotTracked.Font.Style - [fsUnderline];
end;

procedure TdxNavBarSkinVista2ExplorerBarViewInfo.AssignDefaultItemPressedStyle;
begin
  inherited;
  NavBar.DefaultStyles.ItemPressed.Font.Style := NavBar.DefaultStyles.ItemPressed.Font.Style - [fsUnderline];
end;

function TdxNavBarSkinVista2ExplorerBarViewInfo.CanSelectLinkByRect: Boolean;
begin
  Result := True;
end;

function TdxNavBarSkinVista2ExplorerBarViewInfo.GetAbsoluteLinksImageEdges: TRect;
begin
  Result := cxRect(7, 4, 9, 4);
end;

function TdxNavBarSkinVista2ExplorerBarViewInfo.GetGroupBorderOffsets: TRect;
begin
  if TdxNavBarSkinVista2ExplorerBarPainter(Painter).IsSkinAvailable then
    Result := GetSkinElementOffsets(GetHelper.NavBarGroupClient)
  else
    Result := inherited GetGroupBorderOffsets;
end;

function TdxNavBarSkinVista2ExplorerBarViewInfo.GetGroupCaptionHeightAddon: Integer;
begin
  Result := 15;
end;

class function TdxNavBarSkinVista2ExplorerBarViewInfo.GetGroupCaptionImageIndent: Integer;
begin
  Result := 2;
end;

function TdxNavBarSkinVista2ExplorerBarViewInfo.GetGroupCaptionSignSize: TSize;
var
  AElement: TdxSkinElement;
begin
  AElement := GetHelper.NavBarGroupSigns(True);
  if AElement <> nil then
    Result := AElement.Size
  else
    Result := inherited GetGroupCaptionSignSize;
end;

function TdxNavBarSkinVista2ExplorerBarViewInfo.GetGroupEdges: TPoint;
begin
  if not IsThemeActive then
    Result := cxNullPoint
  else
    Result := cxPoint(1, 1);
end;

function TdxNavBarSkinVista2ExplorerBarViewInfo.GetGroupSeparatorWidth: Integer;
begin
  Result := -1;
end;

{ TdxNavBarSkinVista2ExplorerBarPainter }

procedure TdxNavBarSkinVista2ExplorerBarPainter.Assign(Source: TPersistent);
begin
  if Source is TdxNavBarSkinVista2ExplorerBarPainter then
    LookAndFeel := TdxNavBarSkinVista2ExplorerBarPainter(Source).LookAndFeel
  else
    inherited;
end;

procedure TdxNavBarSkinVista2ExplorerBarPainter.DrawBackground;
begin
  if not DrawSkinElement(FSkinBasedPainterHelper.NavBarBackground, Canvas, NavBar.ClientRect) then
    inherited;
end;

procedure TdxNavBarSkinVista2ExplorerBarPainter.DrawGroupBackground(AGroupViewInfo: TdxNavBarGroupViewInfo);
begin
  if not IsSkinAvailable then
    inherited;
end;

procedure TdxNavBarSkinVista2ExplorerBarPainter.DrawGroupBorder(
  AGroupViewInfo: TdxNavBarGroupViewInfo);
begin
  inherited DrawGroupBorder(AGroupViewInfo);
  if not AGroupViewInfo.IsCaptionVisible then
    DrawGroupTopBorder(AGroupViewInfo);
end;

procedure TdxNavBarSkinVista2ExplorerBarPainter.DrawGroupTopBorder(
  AGroupViewInfo: TdxNavBarGroupViewInfo);
var
  AElement: TdxSkinElement;
  R: TRect;
begin
  AElement := FSkinBasedPainterHelper.NavBarGroupButtonCaption;
  if AElement <> nil then
  begin
    cxCanvas.SaveClipRegion;
    try
      R := AGroupViewInfo.ItemsRect;
      cxCanvas.SetClipRegion(TcxRegion.Create(cxRectSetHeight(R, 1)), roSet);
      R.Bottom := R.Top + 1;
      Dec(R.Top, AElement.Size.cy);
      AElement.Draw(cxCanvas.Handle, R);
    finally
      cxCanvas.RestoreClipRegion;
    end;
  end;
end;

procedure TdxNavBarSkinVista2ExplorerBarPainter.DrawItemSelection(
  ALinkViewInfo: TdxNavBarLinkViewInfo);
var
  AState: TdxSkinElementState;
begin
  AState := NavBarObjectStateToSkinState(ALinkViewInfo.State);
  if not DrawSkinElement(FSkinBasedPainterHelper.NavPaneItem((AState = esNormal) and (sSelected in ALinkViewInfo.State)),
    Canvas, ALinkViewInfo.SelectionRect, 0, AState) then
    inherited;
end;

procedure TdxNavBarSkinVista2ExplorerBarPainter.DrawGroupControl(ACanvas: TCanvas;
  ARect: TRect; AGroupViewInfo: TdxNavBarGroupViewInfo);
begin
  if not DrawSkinElement(FSkinBasedPainterHelper.NavBarGroupClient, ACanvas, ARect, 0, esNormal, True) then
    inherited;
end;

procedure TdxNavBarSkinVista2ExplorerBarPainter.DrawGroupControlSplitter(AGroupViewInfo: TdxNavBarExplorerBarGroupViewInfo);
var
  ARect: TRect;
begin
  ARect := cxRectSetBottom(AGroupViewInfo.SplitterRect, AGroupViewInfo.SplitterRect.Top + 1, 1);
  FillRectByColor(Canvas.Handle, ARect, clBtnHighlight);
  ARect := cxRectSetBottom(ARect, ARect.Bottom + 2, 2);
  FillRectByColor(Canvas.Handle, ARect, clBtnFace);
  ARect := cxRectSetBottom(ARect, ARect.Bottom + 1, 1);
  FillRectByColor(Canvas.Handle, ARect, clBtnHighlight);
end;

procedure TdxNavBarSkinVista2ExplorerBarPainter.DrawSeparator(ALinkViewInfo: TdxNavBarLinkViewInfo);
var
  AClipRect, ADrawRect: TRect;
begin
  if (FSkinBasedPainterHelper.NavPaneHeader <> nil) and
    (FSkinBasedPainterHelper.NavPaneCaptionHeight <> nil) then
  begin
    AClipRect := ALinkViewInfo.SeparatorRect;
    ADrawRect := cxRectSetBottom(AClipRect, AClipRect.Bottom, FSkinBasedPainterHelper.NavPaneCaptionHeight.Value);
    DrawElementPart(FSkinBasedPainterHelper.NavPaneHeader, cxCanvas, ADrawRect, AClipRect);
  end
  else
    inherited;
end;

class function TdxNavBarSkinVista2ExplorerBarPainter.GetViewInfoClass: TdxNavBarViewInfoClass;
begin
  Result := TdxNavBarSkinVista2ExplorerBarViewInfo;
end;

class function TdxNavBarSkinVista2ExplorerBarPainter.GetSkinPainterHelperClass: TdxNavBarSkinBasedPainterHelperClass;
begin
  Result := TdxNavBarSkinVista2PainterHelper;
end;

class function TdxNavBarSkinVista2ExplorerBarPainter.SignPainterClass: TdxNavBarCustomSignPainterClass;
begin
  Result := TdxNavBarExplorerBarSignPainter;
end;

function TdxNavBarSkinVista2ExplorerBarPainter.GetMasterLookAndFeel: TcxLookAndFeel;
begin
  Result := LookAndFeel;
end;

function TdxNavBarSkinVista2ExplorerBarPainter.IsSkinNameStored: Boolean;
begin
  Result := SkinNameAssigned;
end;

class function TdxNavBarSkinVista2ExplorerBarPainter.SelectionPainterClass: TdxNavBarCustomSelectionPainterClass;
begin
  Result := TdxNavBarSkinVista2ExplorerBarSelectionPainter;
end;

procedure TdxNavBarSkinVista2ExplorerBarPainter.SetLookAndFeel(AValue: TcxLookAndFeel);
begin
  LookAndFeel.Assign(AValue);
end;

procedure TdxNavBarSkinVista2ExplorerBarPainter.SetSkinName(const AValue: TdxSkinName);
begin
  ColorSchemeName := AValue;
end;

class function TdxNavBarSkinVista2ExplorerBarPainter.GetGroupViewInfoClass: TdxNavBarGroupViewInfoClass;
begin
  Result := TdxNavBarSkinVista2ExplorerBarGroupViewInfo;
end;

class function TdxNavBarSkinVista2ExplorerBarPainter.GetLinkViewInfoClass: TdxNavBarLinkViewInfoClass;
begin
  Result := TdxNavBarSkinVista2ExplorerBarLinkViewInfo;
end;

function TdxNavBarSkinVista2ExplorerBarPainter.GetLookAndFeel: TcxLookAndFeel;
begin
  Result := TdxNavBarSkinVista2PainterHelper(FSkinBasedPainterHelper).FLookAndFeel;
end;

function TdxNavBarSkinVista2ExplorerBarPainter.GetSkinName: TdxSkinName;
begin
  Result := ColorSchemeName;
end;

function TdxNavBarSkinVista2ExplorerBarPainter.GetSkinNameAssigned: Boolean;
begin
  Result := lfvSkinName in LookAndFeel.AssignedValues;
end;

procedure TdxNavBarSkinVista2ExplorerBarPainter.SetSkinNameAssigned(AValue: Boolean);
begin
  if AValue then
    LookAndFeel.AssignedValues := LookAndFeel.AssignedValues + [lfvSkinName]
  else
    LookAndFeel.AssignedValues := LookAndFeel.AssignedValues - [lfvSkinName];
end;

{ TdxNavBarSkinVista2ExplorerBarSelectionPainter }

class procedure TdxNavBarSkinVista2ExplorerBarSelectionPainter.GetColors(
  AState: TdxNavBarObjectStates; ABackColor: TColor; out AFillColor,
  ATopLeftOuterColor, ABottomRightOuterColor, ATopLeftInnerColor,
  ABottomRightInnerColor: TColor);
begin
  inherited;
  AFillColor := clActiveCaption;
end;

{ TdxNavBarSkinVista2ExplorerBarLinkViewInfo }

function TdxNavBarSkinVista2ExplorerBarLinkViewInfo.Font: TFont;
begin
  Result := inherited Font;
  Result.Name := 'Segoe UI';
end;

function TdxNavBarSkinVista2ExplorerBarLinkViewInfo.FontColor: TColor;
const
  ATextColor: array [Boolean] of TColor = (clWindowText, clHighlightText);
begin
  if not IsThemeActive then
    Result := ATextColor[[sSelected, sPressed, sHotTracked] * State <> []]
  else
    Result := inherited FontColor;
end;

{ TdxNavBarSkinVista2ExplorerBarGroupViewInfo }

function TdxNavBarSkinVista2ExplorerBarGroupViewInfo.CaptionBackColor: TColor;
begin
  if [sSelected, sPressed, sHotTracked] * State <> [] then
    if sPressed in State then
      Result := clHotLight
    else
      Result := clActiveCaption
  else
    Result := clWindow;
end;

function TdxNavBarSkinVista2ExplorerBarGroupViewInfo.CaptionBackColor2: TColor;
begin
  Result := CaptionBackColor;
end;

function TdxNavBarSkinVista2ExplorerBarGroupViewInfo.CaptionFont: TFont;
begin
  Result := inherited CaptionFont;
  Result.Style := Result.Style - [fsBold];
  Result.Name := 'Segoe UI';
end;

function TdxNavBarSkinVista2ExplorerBarGroupViewInfo.CaptionFontColor: TColor;
const
  ATextColor: array [Boolean] of TColor = (clWindowText, clHighlightText);
var
  AElement: TdxSkinElement;
begin
  if not IsThemeActive then
    Result := ATextColor[[sSelected, sPressed, sHotTracked] * State <> []]
  else
    with TdxNavBarSkinVista2ExplorerBarPainter(Painter) do
    begin
      AElement := FSkinBasedPainterHelper.NavBarGroupButtonCaption;
      if AElement <> nil then
        Result := AElement.TextColor
      else
        Result := inherited CaptionFontColor;
    end;
end;

function TdxNavBarSkinVista2ExplorerBarGroupViewInfo.GetSplitterSize: Integer;
begin
  Result := 4;
end;

initialization
  dxNavBarViewsFactory.RegisterView(dxNavBarSkinExplorerBarView,
    'SkinVista2ExplorerBarView', TdxNavBarSkinVista2ExplorerBarPainter);
  RegisterClasses([TdxNavBarSkinVista2ExplorerBarPainter]);

finalization
  dxNavBarViewsFactory.UnRegisterView(dxNavBarSkinExplorerBarView);

end.
